package com.electronic.modules.revoke;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.RevokeElectronicSealSignature;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.param.GenerateRevokeElectronicSealSignatureQRCodeParamDTO;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.param.GetDataSignatureValueParamDTO;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.param.QueryQRCodeScannedStatusReParamDTO;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.result.GenerateRevokeElectronicSealSignatureQRCodeResultDTO;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.result.GetDataSignatureValueResultDTO;
import com.cebpubservice.cashare.sdk.electronicsealsignatureandverifysignature.result.QueryQRCodeScannedStatusReResultDTO;
import com.electronic.constant.CebsConstant;
import com.electronic.constant.CommonConstant;
import com.electronic.domain.CebsConfiguration;
import com.electronic.enums.FileTypeEnum;
import com.electronic.enums.QRCodeScannedStatusEnum;
import com.electronic.enums.RevokeSignatureStatusEnum;
import com.electronic.enums.SignStatusEnum;
import com.electronic.exception.ResultCode;
import com.electronic.exception.ServiceException;
import com.electronic.gbt.GBT7_1_1.SES_Signature;
import com.electronic.jwt.JwtProperties;
import com.electronic.jwt.JwtProvider;
import com.electronic.modules.revoke.param.GenerateRevokeSignatureQRCodeDTO;
import com.electronic.modules.revoke.param.QRCodeScannedStatusDTO;
import com.electronic.modules.revoke.param.RevokeSignatureDTO;
import com.electronic.modules.revoke.result.*;
import com.electronic.utils.IFCAUtil;
import com.electronic.utils.IFileUtil;
import com.electronic.utils.IRequestUtil;
import com.itextpdf.forms.PdfAcroForm;
import com.itextpdf.forms.fields.PdfFormField;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.annot.PdfWidgetAnnotation;
import com.itextpdf.signatures.PdfPKCS7;
import com.itextpdf.signatures.SignatureUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchProviderException;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author zyh 
 * ================================
 * Date: 2024/7/25
 * Time: 上午9:40
 * ================================
 */
@Slf4j
public class RevokeService {

    /**
     * 生成撤章二维码
     *
     * @param generateRevokeSignatureQRCodeDTO 文件地址
     * @return
     */
    public static GenerateRevokeSignatureQRCodeVO generateRevokeSignatureQRCode(GenerateRevokeSignatureQRCodeDTO generateRevokeSignatureQRCodeDTO) {
        //初始化SDK
        CebsConfiguration.init(generateRevokeSignatureQRCodeDTO.getCebsSdkProperties());
        //文件在本地路径
        String fileAbsolutePath = generateRevokeSignatureQRCodeDTO.getPath();

        //获取撤章文件最后一个证书序列号
        String fileSignatureCertSn;
        if ("pdf".equals(checkIfPdfExists(generateRevokeSignatureQRCodeDTO.getPath()))) {
            fileSignatureCertSn = getPdfSignatureCertSn(fileAbsolutePath);
        } else {
            //ofd解析
            fileSignatureCertSn = "";
        }
        //组装请求参数
        GenerateRevokeElectronicSealSignatureQRCodeParamDTO paramDTO = new GenerateRevokeElectronicSealSignatureQRCodeParamDTO();
        paramDTO.setSignatureCertSn(fileSignatureCertSn);
        GenerateRevokeElectronicSealSignatureQRCodeResultDTO resultDTO;
        try {
            //调用中招【获取撤章二维码】接口
            log.info("调用中招生成撤章二维码,req:{}", JSON.toJSONString(paramDTO));
            resultDTO = RevokeElectronicSealSignature.generateRevokeElectronicSealSignatureQRCode(paramDTO);
            log.info("调用中招生成撤章二维码,resp:{}", JSON.toJSONString(resultDTO));
        } catch (Exception e) {
            log.error("生成撤章二维码异常, fileId:{}, fileSignatureCertSn:{}", "文件ID", fileSignatureCertSn, e);
            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE,ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE.getMessage());
        }
        //判空
        if (ObjectUtil.isNull(resultDTO)) {
            log.error("调用中招生成撤章二维码响应为空, fileId:{}, fileSignatureCertSn:{}", "文件ID", fileSignatureCertSn);
            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE,ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE.getMessage());
        }
        //组装响应结果
        GenerateRevokeSignatureQRCodeVO vo = BeanUtil.copyProperties(resultDTO, GenerateRevokeSignatureQRCodeVO.class);

        return vo;
    }


    /**
     * 获取撤章二维码扫码状态
     *
     * @param dto
     * @return
     */
    public static QRCodeScannedStatusVO getQRCodeScannedStatus(QRCodeScannedStatusDTO dto) {

        //初始化中招SDK
//        ElectronicSealSignatureAndVerifySignatureSingleton.init(dto.getCebsSdkProperties().getPlatformCode(), dto.getCebsSdkProperties().getServiceUrl(), dto.getCebsSdkProperties().getClientId(), dto.getCebsSdkProperties().getClientSecret(), dto.getCebsSdkProperties().getAccessKeySecret());
        CebsConfiguration.init(dto.getCebsSdkProperties());

        //组装请求参数
        QueryQRCodeScannedStatusReParamDTO paramDTO = new QueryQRCodeScannedStatusReParamDTO();
        paramDTO.setTid(dto.getTid());
        QueryQRCodeScannedStatusReResultDTO resultDTO;
        try {
            //调用中招【获取扫码状态】接口
            log.info("获取中招撤章二维码状态参数,req:{}", JSON.toJSONString(paramDTO));
            resultDTO = RevokeElectronicSealSignature.queryQRCodeScannedStatus(paramDTO);
            log.info("获取中招撤章二维码状态响应,resp:{}", JSON.toJSONString(resultDTO));

        } catch (Exception e) {
            log.error("获取撤章二维码扫码状态异常, tid:{}", dto.getTid(), e);
            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS,ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS.getMessage());
        }
        //判空
        if (ObjectUtil.isNull(resultDTO)) {
            log.error("获取撤章二维码扫码状态响应为空, tid:{}", dto.getTid());
            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS,ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS.getMessage());
        }
        //组装响应结果
        QRCodeScannedStatusVO vo = BeanUtil.copyProperties(resultDTO, QRCodeScannedStatusVO.class);
        //状态描述
        vo.setScannedDesc(QRCodeScannedStatusEnum.getDescByCode(vo.getScannedStatus()));
        //未完成扫码直接返回
        if (!QRCodeScannedStatusEnum.SIGNED.getCode().equals(vo.getScannedStatus())) {
            return vo;
        }
        //调用中招【获取签名值信息】接口
        GetDataSignatureValueParamDTO signatureValueParamDTO = new GetDataSignatureValueParamDTO();
        signatureValueParamDTO.setTid(dto.getTid());
        GetDataSignatureValueResultDTO dataSignatureValue;
        try {
            log.info("调用中招获取签名值信息参数,req:{}", JSON.toJSONString(signatureValueParamDTO));
            dataSignatureValue = RevokeElectronicSealSignature.getDataSignatureValue(signatureValueParamDTO);
            log.info("调用中招获取签名值信息响应,resp:{}", JSON.toJSONString(dataSignatureValue));
            vo.setScannedStatus(QRCodeScannedStatusEnum.SIGNED.getCode());
        } catch (Exception e) {
            log.error("获取签名值异常, tid:{}", dto.getTid(), e);
            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS,ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS.getMessage());
        }
        //判空
        if (ObjectUtil.isNull(dataSignatureValue)) {
            log.error("获取签名值响应为空, tid:{}", dto.getTid());
            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS,ResultCode.ERROR_REVOKE_SIGNATURE_QRCODE_STATUS.getMessage());
        }
        //生成业务流水号
        String transactionId = "revoke:scanned:id" + IdUtil.fastSimpleUUID();

        //获取响应参数中证书序列号
        String signatureCertSn = dataSignatureValue.getSignatureCertSn();
        //校验证书序列号是否一致
//        if (!signatureCertSn.equals(cacheSignatureCertSn)) {
//            log.info("校验撤章二维码证书序列号失败,tid:{},signatureCertSn:{},cacheSignatureCertSn:{}", dto.getTid(), signatureCertSn, cacheSignatureCertSn);
//            throw new ServiceException(ResultCode.ERROR_REVOKE_SIGNATURE_VERIFY_CERT);
//        }
        JwtProperties jwtProperties = new JwtProperties();
        //生成请求token
        String requestToken = JwtProvider.createJWT(CebsConstant.TOKEN_EXPIRE_SECONDS, IRequestUtil.getApplicationId(), IRequestUtil.getApplicationUserId(), IRequestUtil.getBizNo(), transactionId, jwtProperties.getKey());
        //设置响应参数值
        vo.setToken(requestToken);
        return vo;
    }

    /**
     * 撤章
     *
     * @param dto
     * @return
     */
    public static RevokeResultVO revoke(RevokeSignatureDTO dto) {

        //初始化中招SDK
        CebsConfiguration.init(dto.getCebsSdkProperties());
//        ElectronicSealSignatureAndVerifySignatureSingleton.init(dto.getCebsSdkProperties().getPlatformCode(), dto.getCebsSdkProperties().getServiceUrl(), dto.getCebsSdkProperties().getClientId(), dto.getCebsSdkProperties().getClientSecret(), dto.getCebsSdkProperties().getAccessKeySecret());
        log.info("=====中招SDK初始化完成=====");
        String path = dto.getPath();
        if (checkIfPdfExists(path).equals(FileTypeEnum.PDF.name())) {
            //验证PDF文件是否可用
            IFileUtil.verifyPdfUsable(path);
            //检查是否含有电子签章
            if (!IFileUtil.isHasSignature(path)) {
                throw new ServiceException(ResultCode.ERROR_FILE, "文件不含有电子签章");
            }

        }

        //文件在本地路径
        String fileAbsolutePath = path;

        //获取业务请求流水号及缓存数据
        String reqTransactionId = IRequestUtil.getReqTransactionId();
        //生成业务流水号
        String transactionId = IdUtil.fastSimpleUUID();
//        //生成撤章记录
        RevokeSignature revokeSignature = new RevokeSignature();
        revokeSignature.setTransactionId(transactionId);
        revokeSignature.setFileUuid(dto.getPath());
        revokeSignature.setRevokeStatus(RevokeSignatureStatusEnum.REVOKE_ING.getCode());
        //执行撤章
        log.info("执行撤章请求,req:{}", JSON.toJSONString(dto));

        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        //更新撤章记录信息
        revokeSignature.setBeginRevokeTime(now);
        //执行撤章
        String revokeFileKey = null;
        File revokeFile = null;
        try {
            //获取撤章文件本地路径
            String revokeFilePath = fileAbsolutePath;
            //新的路径
            String revokeFileAbsolutePath = dto.getNewPath();

            List<String> revokeSignatureNames = new ArrayList<>();
            if (FileTypeEnum.PDF.getType().equals(checkIfPdfExists(revokeFilePath))) {
                revokeSignatureNames = revokeSignature(fileAbsolutePath, revokeFileAbsolutePath);
            } else {
                //ofo撤章
            }
            //撤章后文件
            revokeFile = new File(revokeFileAbsolutePath);

        } catch (Exception e) {
            log.error("撤章失败,transactionId:{}", "dto.getTransactionId()", e);
//            throw new ServiceException(ResultCode.ERROR_FILE);
            //撤章失败
            revokeSignature.setRevokeStatus(RevokeSignatureStatusEnum.REVOKE_FAIL.getCode());
            revokeSignature.setRevokeRemark(e.getMessage());
        }

        if (ObjectUtil.isNull(revokeSignature)) {
            throw new ServiceException(ResultCode.ERROR_FILE,ResultCode.ERROR_FILE.getMessage());
        }
        //组装响应结果
        RevokeResultVO vo = RevokeResultVO.builder()
                .revokeStatus(revokeSignature.getRevokeStatus())
                .revokeStatusDesc(revokeSignature.getRevokeRemark())
                .transactionId("dto.getTransactionId()")
                .build();
        //已完成撤章，则继续查询撤章后文件信息
        if (SignStatusEnum.SIGN_SUCCESS.getCode().equals(revokeSignature.getRevokeStatus())) {

            vo.setFileName(revokeFile.getName());
            vo.setFileType(checkIfPdfExists(revokeFile.getAbsolutePath()));
            vo.setFileSize(revokeFile.length());
            vo.setFileId("fileEntity.getFileUuid()");

        }
        vo.setRevokeStatus(RevokeSignatureStatusEnum.REVOKE_SUCCESS.getCode());

        return vo;


    }


    /**
     * 判断文件是否存在及文件类型
     *
     * @param relativePath 文件地址
     * @return 文件类型
     */
    private static String checkIfPdfExists(String relativePath) {
        try {
            File file = new File(relativePath);
            // 判断文件是否存在
            if (file.exists()) {
                // 获取文件名
                String fileName = file.getName();
                // 检查文件扩展名是否为.pdf
                if (fileName.endsWith(".pdf")) {

                    return FileTypeEnum.PDF.getType();
                } else if (fileName.endsWith(".ofd")) {
                    return FileTypeEnum.OFD.getType();
                } else {
                    throw new ServiceException(ResultCode.ERROR_FILE_EXT, "撤章文件无效，只支持OFD或PDF文件");
                }
            } else {
                throw new ServiceException(ResultCode.ERROR_FILE_NOT_FOUND, "撤章文件不存在");

            }
        } catch (ServiceException e) {
            throw new ServiceException(ResultCode.ERROR_FILE_NOT_FOUND, "撤章文件不存在");
        }

    }


    public static String getPdfSignatureCertSn(String pdfPath) {
        // 使用PdfReader读取PDF文件
        com.itextpdf.kernel.pdf.PdfReader reader = null;
        try {
            reader = new com.itextpdf.kernel.pdf.PdfReader(pdfPath);
        } catch (IOException e) {
            // 捕获加载文档时的异常，认为文件不可读
            throw new ServiceException(ResultCode.ERROR_FILE, "文件不可读");
        }

        //签名域名称集合
        List<String> signatureNames = null;
        com.itextpdf.kernel.pdf.PdfDocument pdfDoc = null;
        SignatureUtil signUtil = null;
        try {
            pdfDoc = new com.itextpdf.kernel.pdf.PdfDocument(reader);
            // 获取 SignatureUtil 实例
            signUtil = new SignatureUtil(pdfDoc);
            //获取签名域名称集合
            signatureNames = signUtil.getSignatureNames();
        } catch (Exception e) {
            throw new ServiceException(ResultCode.ERROR_FILE, "当前文件未发现已签印章");
        }

        if (CollUtil.isEmpty(signatureNames)) {
            //关闭阅读器
            pdfDoc.close();
            try {
                reader.close();
            } catch (IOException e) {
                throw new ServiceException(ResultCode.ERROR_FILE, "当前文件未发现已签印章");
            }
            throw new ServiceException(ResultCode.ERROR_FILE, "当前文件未发现已签印章");
        }

        List<SignatureInfo> signatureInfoList = new ArrayList<>();
        try {
            //BC的安全模式
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            //获取最后一次签章名称
            for (String signatureName : signatureNames) {
                com.itextpdf.kernel.pdf.PdfDictionary v = signUtil.getSignatureDictionary(signatureName);
                com.itextpdf.kernel.pdf.PdfString contents = v.getAsString(com.itextpdf.kernel.pdf.PdfName.Contents);
                // 获取签名数据
                ASN1InputStream asn1InputStream = new ASN1InputStream(contents.getValueBytes());
                ASN1Sequence seq = (ASN1Sequence) asn1InputStream.readObject();
                asn1InputStream.close();
                //签名算法OID
                String oid = findSignatureOid(seq);
                //判断算法类型
                if (CommonConstant.OID_PKCS.equals(oid)) {
                    //获取签名的pkcs7数据
                    PdfPKCS7 pkcs7 = signUtil.readSignatureData(signatureName);
                    //签章时间
                    Long signTime = pkcs7.getSignDate().getTime().getTime();
                    //证书序列号
                    byte[] serialNum = pkcs7.getSigningCertificate().getSerialNumber().toByteArray();
                    //证书序列号(16进制字符串)
                    String fileSignatureCertSn = Hex.encodeHexString(serialNum);
                    signatureInfoList.add(SignatureInfo.builder().signTime(signTime).signatureCertSn(fileSignatureCertSn).build());
                } else {
                    //电子签章数据
                    SES_Signature sesSignature = SES_Signature.getInstance(seq.getEncoded());
                    //签章者证书
                    X509Certificate certificate = IFCAUtil.readX509Certificate(sesSignature.getCert().getOctets());
                    //证书序列号
                    byte[] serialNum = certificate.getSerialNumber().toByteArray();
                    //证书序列号(16进制字符串)
                    String certSn = Hex.encodeHexString(serialNum);
                    //签署时间
                    Long signTime = sesSignature.getToSign().getTimeInfo().getDate().getTime();
                    signatureInfoList.add(SignatureInfo.builder().signTime(signTime).signatureCertSn(certSn).build());
                }
            }
            //根据签章时间排序
            Collections.sort(signatureInfoList, Comparator.comparingLong(SignatureInfo::getSignTime));
            String fileLastSignatureCertSn = signatureInfoList.get(signatureInfoList.size() - 1).getSignatureCertSn();
            return fileLastSignatureCertSn;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(ResultCode.ERROR_FILE, "解析证书序列号失败");
        }
    }

    /**
     * @param seq 签名数据结构对象
     * @Description 获取签名算法
     */
    public static String findSignatureOid(ASN1Sequence seq) {
        //签名算法OID
        String oid = null;
        //遍历序列中的每个元素，找到第一个Algorithmidentifier类型的对象，用来判断签名使用的国际标准还是国内标准
        for (int i = 0; i < seq.size(); i++) {
            ASN1Encodable obj = seq.getObjectAt(i);
            // 判断是否是Algorithmidentifier类型
            if (obj instanceof AlgorithmIdentifier) {
                oid = ((AlgorithmIdentifier) obj).getAlgorithm().toString();
                break;
                // 如果不是Algorithmidentifier类型，则判断是否是ASN1ObjectIdentifier类型
            } else if (obj instanceof ASN1ObjectIdentifier) {
                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier((ASN1ObjectIdentifier) obj);
                oid = algorithmIdentifier.getAlgorithm().toString();
                break;
            }
        }
        return oid;
    }

    public static List<String> revokeSignature(String sourceFilePath, String revokeFilePath) throws IOException, CertificateException, ParseException, NoSuchProviderException {
        log.info("撤章文件sourceFilePath：{},revokeFilePath:{}", sourceFilePath, revokeFilePath);
        // 使用PdfReader读取PDF文件
        PdfReader reader = new PdfReader(sourceFilePath);
        PdfDocument pdfDoc = new PdfDocument(reader);
        //签章信息集合
        List<SignatureInfo> signatureInfoList = getSignatureInfos(pdfDoc);
        log.info("撤章签名信息数量,signatureInfoListSize:{}", signatureInfoList.size());
        //获取最后一个元素
        SignatureInfo signatureInfo = signatureInfoList.get(signatureInfoList.size() - 1);

        //获取对应批次号
        String batchNumber = signatureInfo.getBatchNumber();
        //查询同一批次签章数量
        List<SignatureInfo> batchSignatureInfoList = signatureInfoList.stream().filter(s -> batchNumber.equals(s.getBatchNumber())).collect(Collectors.toList());
        int batchCount = batchSignatureInfoList.size();
        log.info("撤章同一批次数量,batchCount:{}", batchCount);
        List<String> signatureFieldList;
        //判断批次数量和签章数量是否相等
        if (batchCount != signatureInfoList.size()) {
            //待撤章签名前一个签名域名称
            String revokeSignaturePreviousName = signatureInfoList.get(signatureInfoList.size() - batchCount - 1).getName();
            log.info("撤章revokeSignaturePreviousName:{}", revokeSignaturePreviousName);
            signatureFieldList = batchSignatureInfoList.stream().map(SignatureInfo::getName).collect(Collectors.toList());
            //部分撤章
            doPartRevoke(pdfDoc, revokeFilePath, revokeSignaturePreviousName);
        } else {
            signatureFieldList = signatureInfoList.stream().map(SignatureInfo::getName).collect(Collectors.toList());
            //全部撤章
            doAllRevoke(sourceFilePath, revokeFilePath);
        }
        reader.close();
        return signatureFieldList;
    }

    /**
     * 获取签名域信息
     *
     * @param
     * @return
     */
    private static List<SignatureInfo> getSignatureInfos(com.itextpdf.kernel.pdf.PdfDocument pdfDoc) throws IOException, CertificateException, NoSuchProviderException, ParseException {
        // 获取 SignatureUtil 实例
        SignatureUtil signUtil = new SignatureUtil(pdfDoc);
        List<String> signatureNames = signUtil.getSignatureNames();
        List<SignatureInfo> signatureInfoList = new ArrayList<>();
        //BC的安全模式
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        for (String signatureName : signatureNames) {
            log.info(signatureName);
            //获取批次号
            String batchNumber = signatureName.contains("_") ? signatureName.substring(0, signatureName.lastIndexOf("_")) : signatureName;
            com.itextpdf.kernel.pdf.PdfDictionary v = signUtil.getSignatureDictionary(signatureName);
            com.itextpdf.kernel.pdf.PdfString contents = v.getAsString(com.itextpdf.kernel.pdf.PdfName.Contents);
            // 获取签名数据
            ASN1InputStream asn1InputStream = new ASN1InputStream(contents.getValueBytes());
            ASN1Sequence seq = (ASN1Sequence) asn1InputStream.readObject();
            asn1InputStream.close();
            //签名算法OID
            String oid = findSignatureOid(seq);
            //判断算法类型
            if (CommonConstant.OID_PKCS.equals(oid)) {
                //获取签名的pkcs7数据
                com.itextpdf.signatures.PdfPKCS7 pkcs7 = signUtil.readSignatureData(signatureName);
                //签章时间
                Long signTime = pkcs7.getSignDate().getTime().getTime();
                //证书序列号
                byte[] serialNum = pkcs7.getSigningCertificate().getSerialNumber().toByteArray();
                //证书序列号(16进制字符串)
                String fileSignatureCertSn = Hex.encodeHexString(serialNum);
                signatureInfoList.add(SignatureInfo.builder().name(signatureName).batchNumber(batchNumber).signTime(signTime).signatureCertSn(fileSignatureCertSn).build());
            } else {
                //电子签章数据
                SES_Signature sesSignature = SES_Signature.getInstance(seq.getEncoded());
                //签章者证书
                X509Certificate certificate = IFCAUtil.readX509Certificate(sesSignature.getCert().getOctets());
                //证书序列号
                byte[] serialNum = certificate.getSerialNumber().toByteArray();
                //证书序列号(16进制字符串)
                String certSn = Hex.encodeHexString(serialNum);
                //签署时间
                Long signTime = sesSignature.getToSign().getTimeInfo().getDate().getTime();
                signatureInfoList.add(SignatureInfo.builder().name(signatureName).batchNumber(batchNumber).signTime(signTime).signatureCertSn(certSn).build());
            }
        }
        //根据签章时间排序
        Collections.sort(signatureInfoList, Comparator.comparingLong(SignatureInfo::getSignTime));
        return signatureInfoList;
    }

    /**
     * 部分撤章
     *
     * @param revokeFilePath              撤章文件路径
     * @param revokeSignaturePreviousName 待撤章前一个签名域名称
     */
    private static void doPartRevoke(PdfDocument pdfDoc, String revokeFilePath, String revokeSignaturePreviousName) {
        // 获取 SignatureUtil 实例
        SignatureUtil signUtil = new SignatureUtil(pdfDoc);
        //提取待撤章签名前一个签名的修订版本
        InputStream revisionStream = signUtil.extractRevision(revokeSignaturePreviousName);
        //将提取的修订版本保存为新的PDF文件
        FileUtil.writeFromStream(revisionStream, revokeFilePath);
        //关闭读取器
        pdfDoc.close();
    }

    /**
     * 全部撤章
     *
     * @param sourceFilePath 原路径
     * @param revokeFilePath 撤章文件路径
     */
    private static void doAllRevoke(String sourceFilePath, String revokeFilePath) throws IOException {
        File revokeFile = IFileUtil.filePathToFile(revokeFilePath);
        PdfReader reader = new PdfReader(sourceFilePath);
        PdfDocument pdfDoc = new PdfDocument(reader, new PdfWriter(revokeFile));
        // 获取AcroForm对象
        PdfAcroForm acroForm = PdfAcroForm.getAcroForm(pdfDoc, false);
        if (acroForm != null) {
            Map<String, PdfFormField> fields = acroForm.getFormFields();
            List<String> fieldsToRemove = new ArrayList<>();
            for (Map.Entry<String, PdfFormField> entry : fields.entrySet()) {
                PdfFormField field = entry.getValue();
                try {
                    if (field.getFormType().equals(PdfName.Sig)) {
                        for (PdfWidgetAnnotation widget : field.getWidgets()) {
                            // 移除页面上的注释
                            widget.getPage().removeAnnotation(widget);
                            // 移除引用对象
                            widget.releaseFormFieldFromWidgetAnnotation();
                        }
                        fieldsToRemove.add(entry.getKey());
                    }
                } catch (Exception e) {
                    log.error("移除签名域异常", e);
                }
            }

            // 在遍历结束后移除字段
            for (String fieldName : fieldsToRemove) {
                acroForm.removeField(fieldName);
            }
        }
        //关闭pdfDoc
        pdfDoc.close();
        //关闭读取器
        reader.close();
    }


}